package com.fwtai;

import com.fwtai.builder.IdHelper;
import com.fwtai.builder.IdWorkerOptions;
import com.fwtai.config.ConfigFile;
import com.fwtai.quartz.ToolQuartz;
import com.fwtai.service.AsyncService;
import com.fwtai.service.api.ApiGoodsOrderService;
import com.fwtai.web.TaskHandlerDao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@EnableTransactionManagement
@SpringBootApplication
@EnableAsync
public class LaunchApi implements EnvironmentAware,ApplicationListener<ContextRefreshedEvent>{

  private final TaskHandlerDao taskHandlerDao;

  private final AsyncService asyncService;

  private final ApiGoodsOrderService apiGoodsOrderService;

  public LaunchApi(final TaskHandlerDao taskHandlerDao,final AsyncService asyncService,final ApiGoodsOrderService apiGoodsOrderService){
    this.taskHandlerDao = taskHandlerDao;
    this.asyncService = asyncService;
    this.apiGoodsOrderService = apiGoodsOrderService;
  }

  public static void main(final String[] args){
    final IdWorkerOptions options = new IdWorkerOptions(ConfigFile.workerIdApi);
    options.WorkerIdBitLength = ConfigFile.workerLength;
    options.SeqBitLength = ConfigFile.seqLength;
    IdHelper.setIdGenerator(options);
    SpringApplication.run(LaunchApi.class,args);
  }

  @Override
  public void setEnvironment(final Environment environment){
    final Integer port = environment.getProperty("server.port",Integer.class);
    try {
      System.out.println("http://"+InetAddress.getLocalHost().getHostAddress()+":"+port+"/swagger-ui.html");
    } catch (final Exception ignored){
      System.out.println("http://127.0.0.1:"+port+"/swagger-ui.html");
    }
  }

  @Override
  public void onApplicationEvent(final ContextRefreshedEvent event){
    final List<Long> listOrder = taskHandlerDao.getTimeoutOrder();
    final List<Long> listKids = taskHandlerDao.getMallTimeoutOrder();
    final ExecutorService threadPool = Executors.newCachedThreadPool();
    threadPool.execute(() -> {
      try {
        if(!listOrder.isEmpty()){
          taskHandlerDao.delTimeoutOrder(listOrder);//启动后检查是否有超过30分钟未支付的订单再删除
        }
        if(!listKids.isEmpty()){
          taskHandlerDao.delTimeoutMallOrder(listKids);
        }
      } catch (final Exception ignored){
      }finally{
        threadPool.shutdown();
      }
    });
    addDeliveryAuto();//Api接口更新时，重新加入到任务队列的定时任务
    addAutoAffirm();//积分商城
  }

  /**查询微信支付或积分支付的订单,查询大于等于3天的时间未确认收货的订单*/
  private void addDeliveryAuto(){
    final List<HashMap<String,Object>> list = taskHandlerDao.getOrderConfirmed();
    if(!list.isEmpty()){
      final List<HashMap<String,Object>> listLess = new ArrayList<>(list.size());
      final List<HashMap<String,Object>> listGreater = new ArrayList<>(list.size());
      for(int i = list.size() - 1; i >= 0; i--){
        final HashMap<String,Object> map = list.get(i);
        final Long residue = (Long)map.get("residue");
        map.remove("residue");
        final long result = 259200 - residue;// 60 * 60 * 24 * 3 = 259200,得负数立即执行，得正的数开始计时
        if(result <= 0){
          listLess.add(map);
        }else{
          map.put("result",result);
          listGreater.add(map);
        }
      }
      if(!listLess.isEmpty()){//立即执行
        for(int i = listLess.size() - 1; i >= 0; i--){
          final HashMap<String,Object> map = listLess.get(i);
          final int type = (Integer)map.get("type");
          final long out_trade_no = (Long) map.get("out_trade_no");
          switch (type){
            case 1:
              ToolQuartz.editDelayedResult((String) map.get("transaction_id"),out_trade_no,String.valueOf(type));
              break;
            case 2:
              apiGoodsOrderService.editDelivery(out_trade_no,String.valueOf(type));
              break;
            case 3:
              break;
            default:
              break;
          }

        }
      }
      if(!listGreater.isEmpty()){
        for(int i = listGreater.size() - 1; i >= 0; i--){
          final HashMap<String,Object> map = listGreater.get(i);
          final int type = (Integer)map.get("type");
          final long out_trade_no = (Long) map.get("out_trade_no");
          switch (type){
            case 1://微信支付的订单,需要`查询微信服务器的收货状态,且再处理订单的业务即可`
              ToolQuartz.editDelayedResult((String) map.get("transaction_id"),out_trade_no,String.valueOf(type));
              break;
            case 2://积分支付的订单,无需`查询微信服务器的收货状态,仅需处理订单的业务即可`
              asyncService.addDeliveryAuto((Long) map.get("out_trade_no"),2,(Long)map.get("result"),null);
              break;
            case 3:
              break;
            default:
              break;
          }
        }
      }
    }
  }

  /**查询积分商城的订单,查询大于等于7天的时间未确认收货的订单*/
  private void addAutoAffirm(){
    final List<HashMap<String,Object>> list = taskHandlerDao.getMallOrder();
    if(!list.isEmpty()){
      final List<HashMap<String,Object>> listLess = new ArrayList<>(list.size());
      final List<HashMap<String,Object>> listGreater = new ArrayList<>(list.size());
      for(int i = list.size() - 1; i >= 0; i--){
        final HashMap<String,Object> map = list.get(i);
        final Long residue = (Long)map.get("residue");
        map.remove("residue");
        final long result = 604800 - residue;// 60 * 60 * 24 * 7 = 604800,得负数立即执行，得正的数开始计时
        if(result <= 0){
          listLess.add(map);
        }else{
          map.put("result",result);
          listGreater.add(map);
        }
      }
      if(!listLess.isEmpty()){//立即执行
        for(int i = listLess.size() - 1; i >= 0; i--){
          final HashMap<String,Object> map = listLess.get(i);
          final int type = (Integer)map.get("type");
          final long out_trade_no = (Long) map.get("out_trade_no");
          switch (type){
            case 1:
              ToolQuartz.editAffirmResult((String) map.get("transaction_id"),out_trade_no);
              break;
            case 2:
              apiGoodsOrderService.editAffirm(out_trade_no);
              break;
            case 3:
              break;
            default:
              break;
          }

        }
      }
      if(!listGreater.isEmpty()){
        for(int i = listGreater.size() - 1; i >= 0; i--){
          final HashMap<String,Object> map = listGreater.get(i);
          final int type = (Integer)map.get("type");
          final long out_trade_no = (Long) map.get("out_trade_no");
          switch (type){
            case 1://微信支付的订单,需要`查询微信服务器的收货状态,且再处理订单的业务即可`
              ToolQuartz.editAffirmResult((String) map.get("transaction_id"),out_trade_no);
              break;
            case 2://积分支付的订单,无需`查询微信服务器的收货状态,仅需处理订单的业务即可`
              asyncService.addAutoDelivery((Long) map.get("out_trade_no"),2,(Long)map.get("result"),null);
              break;
            case 3:
              break;
            default:
              break;
          }
        }
      }
    }
  }

  //避免redis存入的数据看不懂!
  @Bean
  @ConditionalOnMissingBean(name = {"redisTemplate"})
  public RedisTemplate<String,Object> redisTemplate(final LettuceConnectionFactory redisConnectionFactory){
    final RedisTemplate<String,Object> template = new RedisTemplate<String,Object>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }

  @Bean
  @ConditionalOnMissingBean
  public StringRedisTemplate stringRedisTemplate(final LettuceConnectionFactory redisConnectionFactory){
    final StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }

  //备份
  public RedisTemplate<String,Object> redisValue(final RedisConnectionFactory factory){
    final RedisTemplate<String,Object> template = new RedisTemplate<>();
    template.setConnectionFactory(factory);
    return template;
  }
}